// Copyright 2007-2008 Rory Plaire (codekaizen@gmail.com)

using System;

namespace NPack.Interfaces
{
    /// <summary>
    /// An interface to a generic matrix.
    /// </summary>
    /// <typeparam name="T">Type of element in the matrix.</typeparam>
    public interface IMatrix<T> : IEquatable<IMatrix<T>>, IComparable<IMatrix<T>>, IComputable<IMatrix<T>>
        where T : IEquatable<T>, IComparable<T>, IComputable<T>, IConvertible
    {
        /// <summary>
        /// Gets the determinant for the matrix, if it exists.
        /// </summary>
        Double Determinant { get; }

        /// <summary>
        /// Gets the number of columns in the matrix.
        /// </summary>
        Int32 ColumnCount { get; }

        /// <summary>
        /// Gets the format of the matrix, either row-major or column-major.
        /// </summary>
        MatrixFormat Format { get; }

        /// <summary>
        /// Gets true if the matrix is singular (non-invertible).
        /// </summary>
        Boolean IsSingular { get; }

        /// <summary>
        /// Gets true if the matrix is invertible (non-singular).
        /// </summary>
        Boolean IsInvertible { get; }

        /// <summary>
        /// Gets the inverse of the matrix, if one exists.
        /// </summary>
        IMatrix<T> Inverse { get; }

        /// <summary>
        /// Gets true if the matrix is square (<c>RowCount == ColumnCount != 0</c>).
        /// </summary>
        Boolean IsSquare { get; }

        /// <summary>
        /// Gets true if the matrix is symmetrical.
        /// </summary>
        Boolean IsSymmetrical { get; }

        /// <summary>
        /// Gets the number of rows in the matrix.
        /// </summary>
        Int32 RowCount { get; }

        /// <summary>
        /// Gets or sets an element in the matrix.
        /// </summary>
        /// <param name="row">The index of the row of the element.</param>
        /// <param name="column">The index of the column of the element.</param>
        /// <returns>The value of the element at the specified row and column.</returns>
        T this[Int32 row, Int32 column] { get; set; }

        /// <summary>
        /// Makes an element-by-element copy of the matrix.
        /// </summary>
        /// <returns>An exact copy of the matrix.</returns>
        IMatrix<T> Clone();

        /// <summary>
        /// Gets a submatrix.
        /// </summary>
        /// <param name="rowIndexes">The indexes of the rows to include.</param>
        /// <param name="startColumn">The starting column to include.</param>
        /// <param name="endColumn">The ending column to include.</param>
        /// <returns>
        /// A submatrix with rows given by <paramref name="rowIndexes"/> and columns 
        /// <paramref name="startColumn"/> through <paramref name="endColumn"/>.
        /// </returns>
        IMatrix<T> GetMatrix(Int32[] rowIndexes, Int32 startColumn, Int32 endColumn);

        /// <summary>
        /// Returns the transpose of the matrix.
        /// </summary>
        /// <returns>The matrix with the rows as columns and columns as rows.</returns>
        IMatrix<T> Transpose();
    }
}